#include "engine.h"
#include "model.h"
#include "render/rendersystem.h"
#include "collision/meshcollider.h"

//animhelper
void animhelper_t::init(renderhierarchy_t* _object)
{
	object=_object;
	anim_num=0;

}

void animhelper_t::start_anim(stringhash anim_name,bool looped,float speed)
{
	if (object->animation)
	{
//		animation_t* id=object->animation->get_anim(anim_name);
		animation_t* id=object->animation->anims.size() ? &object->animation->anims[0] : 0;
		if (id)
		{
			anim[0].id=id;
			anim[0].looped=looped;
			anim[0].speed=speed;
			anim[0].timer=speed>=0 ? 0 : id->length;
			anim_num=1;
		}
	}
}

void animhelper_t::update()
{
	float frame_time=1/60.0f;
	switch (anim_num)
	{
	case 1:
		{
			anim[0].timer+=frame_time*anim[0].speed;

			if (!anim[0].looped)
			{
				float animlength=anim[0].id->length;

				if (anim[0].speed>0)
				{
					if (anim[0].timer>animlength)
					{
						anim[0].timer=animlength;
						anim_num=0;
					}
				}
				else
				{
					if (anim[0].timer<0)
					{
						anim[0].timer=0;
						anim_num=0;
					}
				}

			}
			else
			{
				anim[0].timer=fmodf(anim[0].timer+anim[0].id->length,anim[0].id->length);
			}

			object->set_animation_frame(anim[0].id, anim[0].timer);
			break;
		}
	}
}

DEFINE_ENTITY(model_t,entity_t);
PROPERTY_BINDING_BEGIN(model_t)
	BIND_PROPERTY_DATA(model_t,object,stringhash,&mesh_property_data);
	BIND_PROPERTY(model_t,color,color4f);
	BIND_PROPERTY(model_t,autoanim,bool);
PROPERTY_BINDING_END

model_t::model_t()
{
	object.value=0;
	color.set(1,1,1,1);
	autoanim=true;
}

void model_t::onload()
{
	entity_t::onload();
	if (object.value)
		rendersystem_t::get_3d_object(obj_3d,object);
}

void model_t::init()
{

	if (object.value)
		rendersystem_t::get_3d_object(obj_3d,object);
	animhelper.init(&this->obj_3d);

	if (autoanim)
		animhelper.start_anim("autoloop-anim",true,1);

	entity_t::init();
}

float angle=0;
void model_t::update()
{
	entity_t::update();

	animhelper.update();
	rendernode_t* n=obj_3d.get_node("rotor");

	angle=-DEG2RAD*10;
	if (n)
		n->local_matrix.rotate(n->local_matrix.axis(1),angle);
	n=obj_3d.get_node("pointer");
	if (n)
	{
		n->local_matrix.rotate(n->local_matrix.axis(0),-DEG2RAD/20);
	}
}

void model_t::render()
{
	if (obj_3d.valid() && color.w>0)
	{
		obj_3d.node_buf[0].local_matrix=getworldmtx();
		obj_3d.object_color=color;
		RSYS->render_object(&obj_3d);
#ifdef LEO_DESIGNER
		obj_3d.selected=this->selected;
#endif
	}
}

void model_t::exit()
{
	entity_t::exit();
}

model_t::~model_t()
{
}

#ifdef LEO_DESIGNER
void model_t::onchangeproperty(const stringhash& propname)
{
	entity_t::onchangeproperty(propname);

	if (propname=="object")
	{
		if (object.value)
		{
			obj_3d.node_buf.clear();
			rendersystem_t::get_3d_object(obj_3d,object);
		}
	}
}
#endif

DEFINE_ENTITY(modelcollider_t,entity_t);
PROPERTY_BINDING_BEGIN(modelcollider_t)
//BIND_PROPERTY_DATA(modelcollider_t,object,stringhash,&mesh_property_data);
PROPERTY_BINDING_END

modelcollider_t::modelcollider_t()
{
//	object.value=0;
	collibuf_index=-1;
	generated=false;
}

void modelcollider_t::onload()
{
	entity_t::onload();
/*
	if (object.value)
		rendersystem_t::get_3d_object(obj_3d,object);

	if (obj_3d.valid())
	{
		generate_meshcolliders(obj_3d.node_buf,colliders);
	}
*/
}

void modelcollider_t::init()
{
	if (!generated && parent->isa(model_t::get_class_typeid()))
	{
		model_t* p=(model_t*)parent;
		generate_meshcolliders(p->obj_3d.node_buf,colliders);
		generated=true;
	}
	entity_t::init();
	ASSERT(collibuf_index==-1);
	collibuf_index=colliworld.size();
	colliworld.push_back(this);
}

void modelcollider_t::update()
{
	entity_t::update();

}

void modelcollider_t::render()
{
/*
	if (obj_3d)
	{
		obj_3d->local_matrix=getworldmtx();
		obj_3d->node_color=color;
		RSYS->render_object(obj_3d);
	}
*/
}

void modelcollider_t::exit()
{
	entity_t::exit();
	ASSERT(collibuf_index!=-1);
	colliworld[colliworld.size()-1]->collibuf_index=collibuf_index;
	unordered_erase(colliworld,(uint32)collibuf_index);
	collibuf_index=-1;
}

modelcollider_t::~modelcollider_t()
{
}

bool modelcollider_t::sphere_intersection(float3& hit_pos, float3& hit_normal, const float3& center, float radius)
{
	for (unsigned int n=0; n<colliders.size(); ++n)
	{
		if (colliders[n].intersect_sphere(hit_pos, hit_normal, getworldmtx(), center, radius))
		{
			return true;
		}
	}

	return false;
}


#ifdef LEO_DESIGNER
void modelcollider_t::onchangeproperty(const stringhash& propname)
{
	entity_t::onchangeproperty(propname);

/*
	if (propname=="object")
	{
		if (object.value)
		{
			rendersystem_t::get_3d_object(obj_3d,object);
		}

		colliders.clear();
		if (obj_3d.valid())
		{
			generate_meshcolliders(obj_3d.node_buf,colliders);
		}
	}
*/
}
#endif

vector<modelcollider_t*> colliworld;

bool sphere_background_collision(const float3& center, float radius,float3& hitpos, float3& hitnormal)
{
	for (unsigned int n=0; n<colliworld.size(); ++n)
	{
		if (colliworld[n]->sphere_intersection(hitpos, hitnormal, center, radius))
			return true;
	}

	return false;
}

void start_anim(model_t* m,float speed,bool loop)
{
	ASSERT(m->isa(model_t::get_class_typeid()));
	m->animhelper.start_anim("autoloop-anim",loop,speed);
}

void stop_anim(model_t* m)
{
	ASSERT(m->isa(model_t::get_class_typeid()));
	m->animhelper.anim_num=0;
}

bool is_anim_playing(model_t* m)
{
	ASSERT(m->isa(model_t::get_class_typeid()));
	return m->animhelper.anim_num>0;
}

void set_anim_speed(model_t* m,float speed)
{
	ASSERT(m->isa(model_t::get_class_typeid()));
	m->animhelper.anim[0].speed=speed;
}

#include "script/script.h"
script_fn_registering_begin(animation)
register_script_fn("void start_anim(int,float,bool)",start_anim);
register_script_fn("void stop_anim(int)",stop_anim);
register_script_fn("bool is_anim_playing(int)",is_anim_playing);
register_script_fn("void set_anim_speed(int,float)",set_anim_speed);
script_fn_registering_end
script_fn_registering_begin(collision)
register_script_fn("bool sphere_background_collision(const float3& in spherecenter, float sphereradius,float3& out hitpos, float3& out hitnormal)",sphere_background_collision);
script_fn_registering_end
